﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;

namespace SplitEncodeDecodeComp
{
    class SplitEncDecCombine
    {
        private const int RIJNDAEL_SECRET_KEY_SIZE_BITS = 256;
        private const int RIJNDAEL_INITIAL_VECTOR_SIZE_BITS = 128;
        private const int BUFFER_SIZE = 1024 * 1024;
        private const string PASSWORD = "parola";


        static void SplitFile(string path)
        {
            int fileNameNumber = 0;
            Directory.CreateDirectory("Files");
            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
            using (fs)
            {
                while (fs.Position != fs.Length)
                {
                    byte[] buffer = new byte[BUFFER_SIZE];
                    while (true)
                    {
                        int bytesRead = fs.Read(buffer, 0, buffer.Length);
                        if (bytesRead == 0)
                        {
                            break;
                        }
                        string fileName = string.Format("filePart{0:000}.part", fileNameNumber);
                        FileStream wfs = new FileStream("Files\\" + fileName, FileMode.Create, FileAccess.Write);
                        using (wfs)
                        {
                            byte[] encryptedBytes = EncryptBytes(buffer, PASSWORD);
                            wfs.Write(encryptedBytes, 0, buffer.Length);
                        }
                        fileNameNumber++;
                    }
                }
            }
        }

        static void PutFileBackTogether(string path)
        {
            FileStream bigFile = new FileStream("LecturesNew.rar", FileMode.OpenOrCreate, FileAccess.Write);
            using (bigFile)
            {
                DirectoryInfo dir = new DirectoryInfo(path);
                foreach (FileInfo file in dir.GetFiles())
                {
                    FileStream smallFile = new FileStream(file.FullName, FileMode.Open, FileAccess.Read);
                    using (smallFile)
                    {
                        byte[] fileBytes = new byte[smallFile.Length];
                        int bytesRead = smallFile.Read(fileBytes, 0, (int)smallFile.Length);
                        byte[] decryptedBytes = DecryptBytes(fileBytes, PASSWORD);
                        bigFile.Write(decryptedBytes, 0, bytesRead);
                    }
                }
            }
        }

        private static ICryptoTransform CreateRijndaelEncryptor(string password)
        {
            byte[] salt = Encoding.ASCII.GetBytes(password.Length.ToString());
            PasswordDeriveBytes passwordDerivedBytes = new PasswordDeriveBytes(password, salt);
            byte[] secretKey = passwordDerivedBytes.GetBytes(RIJNDAEL_SECRET_KEY_SIZE_BITS / 8);
            byte[] initialVector = passwordDerivedBytes.GetBytes(RIJNDAEL_INITIAL_VECTOR_SIZE_BITS / 8);
            RijndaelManaged RijndaelCipher = new RijndaelManaged();
            ICryptoTransform encryptor = RijndaelCipher.CreateEncryptor(secretKey, initialVector);
            return encryptor;
        }

        private static byte[] EncryptBytes(byte[] bytesToEncrypt, string password)
        {
            ICryptoTransform encryptor = CreateRijndaelEncryptor(password);
            MemoryStream memoryStream = new MemoryStream();
            CryptoStream cryptoStream =
                new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
            using (cryptoStream)
            {
                cryptoStream.Write(bytesToEncrypt, 0, bytesToEncrypt.Length);
                cryptoStream.FlushFinalBlock();
                byte[] encryptedBytes = memoryStream.ToArray();
                return encryptedBytes;
            }
        }

        private static ICryptoTransform CreateRijndaelDecryptor(string password)
        {
            byte[] salt = Encoding.ASCII.GetBytes(password.Length.ToString());
            PasswordDeriveBytes passwordDerivedBytes = new PasswordDeriveBytes(password, salt);
            byte[] secretKey = passwordDerivedBytes.GetBytes(RIJNDAEL_SECRET_KEY_SIZE_BITS / 8);
            byte[] initialVector = passwordDerivedBytes.GetBytes(RIJNDAEL_INITIAL_VECTOR_SIZE_BITS / 8);
            RijndaelManaged RijndaelCipher = new RijndaelManaged();
            ICryptoTransform decryptor = RijndaelCipher.CreateDecryptor(secretKey, initialVector);
            return decryptor;
        }

        private static byte[] DecryptBytes(byte[] encryptedBytes, string password)
        {
            ICryptoTransform encryptor = CreateRijndaelDecryptor(password);
            MemoryStream encryptedBytesStream = new MemoryStream(encryptedBytes);
            MemoryStream decryptedBytesStream = new MemoryStream();
            CryptoStream cryptoStream =
                new CryptoStream(encryptedBytesStream, encryptor, CryptoStreamMode.Read);
            using (cryptoStream)
            {
                byte[] buffer = new byte[encryptedBytes.Length];
                while (true)
                {
                    int bytesRead = cryptoStream.Read(buffer, 0, buffer.Length);
                    if (bytesRead == 0)
                    {
                        break;
                    }
                    decryptedBytesStream.Write(buffer, 0, bytesRead);
                }
                byte[] decryptedBytes = decryptedBytesStream.ToArray();
                return decryptedBytes;
            }
        }

        static void Main()
        {
            SplitFile(@"C:\Users\Academy\Documents\Visual Studio 2010\Projects\netessentials" +
                @"\TestGeneratorAIMI\StreamExercise\SplitEncodeDecodeComp\bin\Debug\Lectures.rar");
            PutFileBackTogether(@"C:\Users\Academy\Documents\Visual Studio 2010\Projects\netessentials" +
                @"\TestGeneratorAIMI\StreamExercise\SplitEncodeDecodeComp\bin\Debug\Files");
        }
    }
}
